/********************************************************
 *
 * FILE NAME:   buffer.h
 *
 * DESCRIPTION:
 *  Template buffer for primitive types
 *
 ********************************************************/

#ifndef BUFFER_H
#define BUFFER_H

/********************************************************/
/*              Includes                                */
/********************************************************/
#include <cstddef>
#include <type_traits>

/********************************************************/
/*              Defines                                 */
/********************************************************/

/********************************************************/
/*              Macros                                  */
/********************************************************/

/********************************************************/
/*              Typedefs                                */
/********************************************************/
template <class T> class Buffer;

template <class T> class Buffer
{
    static_assert(std::is_fundamental<T>::value, "Buffer can only be of primitive types");

    /********************************************************/
    /*              Typedefs                                */
    /********************************************************/
    public:

    protected:

    private:

    /********************************************************/
    /*              Functions Declarations                  */
    /********************************************************/
    public:
        /********************************************************
         * Function Name    :   Buffer
         *
         * Description      :   Constructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   size_t size = size (capacity) of the buffer
         *
         * Returns      	:
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        Buffer(size_t size)
        {
            _data = new T[size];
            _size = size;
            _start = 0;
        }

        /********************************************************
         * Function Name    :   Buffer
         *
         * Description      :   Destructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        ~Buffer()
        {
            delete[] _data;
        }

        /********************************************************
         * Function Name    :   size
         *
         * Description      :   Get Buffer size (capacity)
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:   buffer size (capacity)
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        size_t size()
        {
            return _size;
        }

        /********************************************************
         * Function Name    :   size
         *
         * Description      :   Clear Buffer
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        void clear()
        {
            for(size_t i = 0; i < _size; ++i)
            {
                _data[i] = 0;
            }
        }

        /********************************************************
         * Function Name    :   rotate
         *
         * Description      :   Rotate Buffer for arbitrary number of places in any direction
         *
         * Side effects     :
         *
         * Comment          :   if places = -1 then buffer[1] -> buffer[0]
         *
         * Parameters       :   int places = number of places for that buffer would be rotated
         *
         * Returns      	:
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        void rotate(int places)
        {
            places = _start - places;
            places %= (int) _size;
            places += _size;
            places %= (int) _size;
            _start = places;
        }

        /********************************************************
         * Function Name    :   operator[]
         *
         * Description      :   Element acces operator for writing
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   size_t index = index of the element
         *
         * Returns      	:   reference to the element
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        T &operator[](size_t index)
        {
            index += _start;
            index %= _size;
            return _data[index];
        }

        /********************************************************
         * Function Name    :   operator[]
         *
         * Description      :   Element acces operator for reading
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   size_t index = index of the element
         *
         * Returns      	:   constant reference to the element
         *
         * Reviewed by      :   draganmarjanovic10@gmail.com, v_duschan@hotmail.com
         *
         ********************************************************/
        const T &operator [](size_t index) const
        {
            index += _start;
            index %= _size;
            return _data[index];
        }

    protected:

    private:

    /********************************************************/
    /*              Variables Declarations                  */
    /********************************************************/
    public:

    protected:

    private:
        T *_data;
        size_t _size;
        size_t _start;

};

/********************************************************/
/*              Functions Declarations                  */
/********************************************************/

/********************************************************/
/*              Variables Declarations (IMPORT)         */
/********************************************************/

#endif /* BUFFER_H */
